/* =========================================================================
 *
 *   The traffic processor.
 *
 *   Development by Sedelnikov Alexander (Bigking).
 *
 * =========================================================================
 */

#include "processor.h"
#include "log.h"


//-----------------------------------------------------------------------//
cprocessor::cprocessor() : cthread()
{
    job_complite = true;
    was_error    = false;
}


//-----------------------------------------------------------------------//
cprocessor::~cprocessor()
{
}


//-----------------------------------------------------------------------//
bool cprocessor::complite()
{
    return job_complite;
}


//-----------------------------------------------------------------------//
bool cprocessor::error()
{
    return was_error;
}


//-----------------------------------------------------------------------//
uint cprocessor::check_by_class( ulong           ip,
                                 ushort          port,
                                 ushort          protocol,
                                 ctraffic_class *tc )
{
    ccondition         *c;

    if( tc == NULL )
        return EQ_STATE_ACCEPT;

    c = tc->start_condition;

    while( c != NULL )
    {
        if( c->type == CND_TYPE_NET )
        {
            if( ( ip & c->mask ) ==
                c->net )
            {
                if( c->eq_state == EQ_STATE_ACCEPT )
                    return EQ_STATE_ACCEPT;
                if( c->eq_state == EQ_STATE_CANCEL )
                    return EQ_STATE_CANCEL;
                c = c->eq_next;
            }
            else
            {
                if( c->not_eq_state == EQ_STATE_ACCEPT )
                    return EQ_STATE_ACCEPT;
                if( c->not_eq_state == EQ_STATE_CANCEL )
                    return EQ_STATE_CANCEL;
                c = c->not_eq_next;
            }
        }
    }

    return EQ_STATE_CANCEL;
}


//-----------------------------------------------------------------------//
void cprocessor::set_hash_table( chash_table<trf_gth>  *hashtbl )
{
    this->hash = hashtbl;
}


//-----------------------------------------------------------------------//
void cprocessor::set_parser    ( cparser               *parser  )
{
    this->parser = parser;
}


//-----------------------------------------------------------------------//
int  cprocessor::thread_run    ( void )
{
    job_complite = false;
    return cthread::thread_run();
}


//-----------------------------------------------------------------------//
void cprocessor::thread_running( void )
{
    was_error           = false;

    parser_item         item;
    trf_gth             trf;

    int                 row_index;
    ulong               ip_src_dst[ 2 ];
    bool                ip_accept[ 2 ];

    ushort              ports[ 2 ];

    ctraffic_class     *tc;

    try
    {

        while( parser->get_next( item ) == 0 )
        {
            tc = cconfig::get_start_traffic_class();

            while( tc != NULL )
            {
                if( tc->classify_hole )
                {
                    tc = tc->next_class;
                    continue;
                }

                ip_src_dst[ 0 ] = item.ip_src;
                ip_src_dst[ 1 ] = item.ip_dst;
                ports[ 0 ]      = item.port_src;
                ports[ 1 ]      = item.port_dst;

                ip_accept[ 0 ]  = true;
                ip_accept[ 1 ]  = true;

                if( tc->start_condition != NULL )
                {
                    for( row_index = 0; row_index < 2; row_index++ )
                    {
                        if( row_index == 0 && !tc->process_src )
                            continue;
                        if( row_index == 1 && !tc->process_dst )
                            continue;

                        ip_accept[ row_index ] = check_by_class(
                            ip_src_dst[ row_index ],
                            ports[ row_index ],
                            item.protocol,
                            tc ) == EQ_STATE_ACCEPT;
                    }
                }

                if( ip_accept[ 0 ] && ip_accept[ 1 ] )
                {
                    if( check_by_class( item.ip_src,
                            item.port_src,
                            item.protocol,
                            cconfig::get_classify_filter_class() ) == EQ_STATE_ACCEPT )
                    {
                        trf.ip         = item.ip_src;
                        trf.tc_id      = tc->internal_id;
                        trf.volume_in  = 0;
                        trf.volume_out = item.bytes;
                        hash->add( trf );
                    }

                    if( check_by_class( item.ip_dst,
                            item.port_dst,
                            item.protocol,
                            cconfig::get_classify_filter_class() ) == EQ_STATE_ACCEPT )
                    {
                        trf.ip         = item.ip_dst;
                        trf.tc_id      = tc->internal_id;
                        trf.volume_in  = item.bytes;
                        trf.volume_out = 0;
                        hash->add( trf );
                    }

                    break;
                }

                tc = tc->next_class;
            }
        }

        parser->end();
    }
    catch( cexception &exc )
    {
        was_error         = true;
        logfatal( "%s", exc.get_formated_message() );
    }


    job_complite = true;
}
